using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEngine;

/// <summary>
/// HTN树用来规划和执行短交互行为, 语境信息短, 需要配合外部环境跑起来更加丰富的行为 , 先跑量
/// </summary>
public class VHTN
{
    public class Scope
    {
        public bool exit = false;
        public Dictionary<string, object> table = new();
        public T Get<T>(string name)
        {
            if (table.TryGetValue(name, out var value))
            {
                return (T)value;
            }
            else return (T)default;
        }
        public void Set(string name, object param)
        {
            table[name] = param;
        }
        public float livetime;
        public bool Catch(string waitCatchName) => table.ContainsKey(waitCatchName);
        public MultiQueue<string> taskQueue;
    }
    /// <summary>
    /// 多级队列,根据优先级来处理弹出不同的节点
    /// </summary>
    public class MultiQueue<T>
    {
        public List<Queue<T>> queues;
        public int order;
        public bool TryPeek(out T result)
        {
            while (queues[order].Count <= 0)
            {
                if (--order == -1)
                {
                    result = default;
                    return false;
                }
            }
            result = queues[order].Peek();
            return true;
        }

        public bool TryDequeue(out T result)
        {
            if (TryPeek(out result))
            {
                queues[order].Dequeue();
                return true;
            }
            result = default;
            return false;
        }

        public T Dequeue() => queues[order].Dequeue();

        public MultiQueue(List<T> mainQueue)
        {
            queues = new List<Queue<T>>()
            {
                new Queue<T>(mainQueue)
            };
        }
        public void LevelUp(List<T> mainQueue) => queues[++order] = new Queue<T>(mainQueue);
    }

    public void Expense(VHTNnode originNode, Scope scope, VActBehaviour behaviour, VHTNBlock block)
    {
        //记录block信息
        behaviour.curRunningBlock = block;

        if (scope.taskQueue == null) scope.taskQueue = new MultiQueue<string>(originNode.childNodes); //说明有继承信息

        string peekNodeName = "";
        string processingNodeName = ""; //其实这个是临时一位的缓冲,避免大量读写taskQueue
        VHTNnode node;
        while (!string.IsNullOrEmpty(processingNodeName) || scope.taskQueue.TryPeek(out peekNodeName))
        {
            if (!string.IsNullOrEmpty(processingNodeName)) //判断这个节点是谁生产的
            {
                node = ToNode(processingNodeName);
                processingNodeName = "";
            }
            else
            {
                scope.taskQueue.Dequeue();
                node = ToNode(peekNodeName);
            }
            //中间写控制流相关

            block.HTNodePath.Add(node.name);

            if (node.isLinear) //线性节点,直接注册
            {
                block.sequence.Add(node.function(scope, behaviour));
            }
            else if (node.isInteractor) //这里可以用yield , 也可以把状态信息继承给下一个flaten
            {
                block.sequence.Add(new FuncObserver()
                {
                    start = () => node?.execute(scope, behaviour),
                    complete = () => node.compelete(scope, behaviour),
                    end = () =>
                    {
                        int selectIndex = node.check(scope, behaviour);
                        var selectedNode = ToNode(node.childNodes[selectIndex]);
                        Expense(selectedNode, scope, behaviour, new VHTNBlock());
                    }
                });
                break;
            }
            else if (node.isSelector) //where会直接走到这里a
            {
                int selectIndex = node.check(scope, behaviour);
                processingNodeName = node.childNodes[selectIndex];
            }
            else //单纯的分流节点, 进入下一级别处理
            {
                scope.taskQueue.LevelUp(node.childNodes);
            }
        }
        block.Start(); //走到这个地方说明本阶段的行为已经被编排完全了
    }


    public void Sample()
    {
        var node1 = new VHTNnode()
        {
            name = "SitThere",
            childNodes = new()
            {
                Redirect("LerpThere"),
                Redirect("TurnBackwardToThere"),
                Redirect("SitAtPoint")
            }
        };
        //增加一个机制， 部分节点可以根据缓冲区内容进行分支，甚至可以提前结束分支
        var node2 = new VHTNnode()
        {
            name = "FetchObject",
            childNodes = new()
            {
                Redirect("WhereIs"), //where is 可以
                Redirect("LerpThere"),
                Redirect("PickUp"),
                Redirect("Give"),
                Redirect("ReturnOri")
            }
        };

        gloable.Add(node1);
        gloable.Add(node2);
    }
    public List<VHTNnode> gloable = new();
    public void Init()
    {
        VHTNnode node;
        node = new VHTNnode()
        {
            name = "WalkThere",
            function = (scope, behaviour) =>
            {
                var processor = behaviour.processor;
                var agent = processor.mechine.agent;
                var position = behaviour.GetParam<Vector3>("position");
                //这里很有可能需要处理时延
                // agent.SetDestination(position);
                FuncObserver observer = new FuncObserver()
                {
                    complete = () =>
                    {
                        return agent.remainingDistance <= agent.stoppingDistance; //closeEnough
                    },
                    tick = () =>
                    {
                        processor.Continue("Walk");//播放走路动画
                    },
                    end = () =>
                    {
                        processor.ContinueState();
                    }
                };
                //前提是能走的过去
                return observer;
            }
        };
        gloable.Add(node);

        node = new VHTNnode()
        {
            name = "LerpThere",
            function = (scope, behaviour) =>
            {
                var processor = behaviour.processor;
                var agent = processor.mechine.agent;
                var position = scope.Get<Vector3>("position");
                //这里很有可能需要处理时延
                // agent.SetDestination(position);
                FuncObserver observer = new FuncObserver()
                {
                    complete = () =>
                    {
                        return Vector3.Distance(processor.transform.position, position) <= 0.5f;
                    },
                    tick = () =>
                    {
                        processor.transform.position = Vector3.Lerp(processor.transform.position, position, 0.01f);
                        processor.Continue("Walk");//播放走路动画
                    },
                    end = () =>
                    {
                        processor.ContinueState();
                    }
                };
                //前提是能走的过去
                return observer;
            }
        };
        gloable.Add(node);

        node = new VHTNnode()
        {
            name = "ReturnOri",
            function = (scope, behaviour) =>
            {
                var processor = behaviour.processor;
                var agent = processor.mechine.agent;
                var position = scope.Get<Vector3>("OriPos");
                //这里很有可能需要处理时延
                // agent.SetDestination(position);
                FuncObserver observer = new FuncObserver()
                {
                    complete = () =>
                    {
                        return Vector3.Distance(processor.transform.position, position) <= 0.5f;
                    },
                    tick = () =>
                    {
                        processor.transform.position = Vector3.Lerp(processor.transform.position, position, 0.01f);
                        processor.Continue("Walk");//播放走路动画
                    },
                    end = () =>
                    {
                        processor.ContinueState();
                    }
                };
                //前提是能走的过去
                return observer;
            }
        };
        gloable.Add(node);

        node = new VHTNnode()
        {
            name = "TurnToThere",
            function = (scope, behaviour) =>
            {
                var position = behaviour.GetParam<Vector3>("position");
                var transform = behaviour.transform;
                var angle = behaviour.GetRotationToTarget(position);
                float rotateSpeed = 1f;
                //应该有Socpe的概念，变量归属于某一个域内，集体分配和销毁
                Quaternion startRotation = transform.rotation;
                Quaternion targetRotation = startRotation * Quaternion.Euler(0, angle, 0);
                float duration = (Mathf.Abs(angle) / 180) / rotateSpeed; // 假设旋转的总时间为1秒钟
                float startTime = Time.time;
                TObserver turnObserver = new TObserver()
                {
                    duration = duration,
                    tickType = 1,
                    tick = () =>
                    {
                        float ratio = (Time.time - startTime) / duration;
                        transform.rotation = Quaternion.Slerp(startRotation, targetRotation, ratio);
                    },
                    end = () => transform.rotation = targetRotation
                };//延后调用
                return turnObserver;
            }
        };

        gloable.Add(node);


        node = new VHTNnode()
        {
            name = "WhereIs",
            childNodes = new()
            {
                Redirect(""), //空节点
                Redirect("Ask"),
            },
            check = (scope, behaviour) =>
            {
                var w = scope.Get<string>("Where");
                if (w != null) return 0;
                else return 1;
            }
        };
        gloable.Add(node);

        node = new VHTNnode()
        {
            name = "Ask", //实际是交互节点，等待用户输入orLLM生成 -->提供改树能力
            childNodes = new()
            {
                Redirect("GoOn"),
                Redirect("End")
            },
            execute = (scope, behaviour) => Debug.Log("到底在哪里啊?"),
            compelete = (scope, behaviour) => scope.livetime > 5f || scope.Catch("Answer"),
            check = (scope, behaviour) =>
            {
                var answer = scope.Get<string>("Answer");
                if (answer != null) return 0;
                return 1;
            },
        };
        gloable.Add(node);

        node = new VHTNnode()
        {
            name = "PickUp",
            function = (scope, behaviour) =>
            {
                var target = scope.Get<GameObject>("Target");
                var clip = "PickUp".ToAnimationClip();
                var action = new TObserver()
                {
                    start = () => behaviour.processor.ContinueState(clip),
                    duration = clip.averageDuration,
                };
                action.tick = () =>
                {
                    if (action.now > 0.5f) behaviour.Attach(target);
                };
                //应该等动画播放到特定时机，且一直附着在手上， 物体的拾取动画由所在空间和物体共同决定
                return action;
            }
        };
        gloable.Add(node);

        node = new VHTNnode()
        {
            name = "Give",
            function = (scope, behaviour) =>
            {
                var target = scope.Get<GameObject>("Target");
                var clip = "Give".ToAnimationClip();
                var action = new TObserver()
                {
                    start = () => behaviour.processor.ContinueState(clip),
                    duration = clip.averageDuration,
                    end = () => behaviour.DeAttach(target)
                };
                return action;
            }
        };
        gloable.Add(node);

        node = new VHTNnode()
        {
            name = "GoOn",
        };
        gloable.Add(node);

        Sample();
    }
    //public VHTNnode Find(string name) => gloable.Find(x => x.name == name);

    public string Redirect(string name) => name;
    public VHTNnode ToNode(string name) => gloable.Find(x => x.name == name);
}

public class VHTNnode
{
    public List<string> childNodes;
    public string name;

    public Action<VHTN.Scope, VActBehaviour> execute;
    public Func<VHTN.Scope, VActBehaviour, Observer> function;
    public Func<VHTN.Scope, VActBehaviour, int> check;
    public Func<VHTN.Scope, VActBehaviour, bool> compelete; // 认为有一个等待节点则是block尾部

    public bool isLinear => function != null;
    public bool isInteractor => compelete != null;
    public bool isSelector => check != null;

    public VHTNnode() { }
    public VHTNnode(Func<VActBehaviour, Observer> func) { }

    public string GetResultNode(VHTN.Scope scope, VActBehaviour behaviour) => childNodes[check(scope, behaviour)];

}
[Serializable]
public class VHTNBlock
{
    [ListDrawerSettings(Expanded = true)]
    public List<string> HTNodePath = new();
    public List<Observer> sequence = new();
    public void Start()
    {
        for (int i = 1; i < sequence.Count; i++)
        {
            sequence[i - 1].Next(sequence[i]);
        }
        sequence[0].Subscribe();
        //还可以在尾部链上end加一个回调来监听完全
    }
}

public interface IExecuteable
{
    public VActBehaviour Behaviour => null;
}
